package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.mapper.UserMapper;
import com.example.java_gobang.model.User;
import com.example.java_gobang.service.RoomService;
import com.example.java_gobang.tools.GameRequest;
import com.example.java_gobang.tools.GameResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2022-08-16
 * Time: 12:13
 */
//表示一个游戏房间
@Data
public class Room {
    //使用字符串 方便生成唯一值
    private String roomId;

    //两个玩家
    private User user1;
    private User user2;

    //棋盘 约定使用 0 代表当前位置未落子 初始化好的二维数组为 全0 使用1代表user1落子位置 使用2代表user2落子位置
    //服务器这里的二维数组有三个功能：进行判定胜负 玩家1和玩家2的子都在哪

    //客户端的二维数组有两个功能：判断有没有子 避免重复落子 画子

    //一般游戏的关键信息的判定是交给后端的


    private int[][] board = new int[15][15];

    private static final int maxRow = 15;
    private static final int maxCol = 15;

    //先手方的玩家 id
    private int whiteUser;
    //使用 UUID 管理房间号 唯一身份标识 一组 16进制 表示的数字 两次调用此算法 生成的字符串都是不相同的

    //通过入口计入的 context 就可以手动注入
    public Room() {
        roomId = UUID.randomUUID().toString();
        onlineUserManager = JavaGobangApplication.context.getBean(OnlineUserManager.class);
        roomService = JavaGobangApplication.context.getBean(RoomService.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }

    private ObjectMapper objectMapper = new ObjectMapper();

    private UserMapper userMapper;


    private OnlineUserManager onlineUserManager;


    private RoomService roomService;
    //处理落子操作
    //记录当前落子的位置，进行胜负判定，给客户端返回响应
    public void putChess(String Reqjson) throws IOException {
        //1、记录当前落子位置
        GameRequest request = objectMapper.readValue(Reqjson,GameRequest.class);
        GameResponse response = new GameResponse();

        //当前这个子是玩家1落  还是玩家2 落的 往数组里写 1 还是 2
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;

        int row = request.getRow();
        int col = request.getCol();

        if(board[row][col] != 0){
            //此处为了程序更加稳定 在服务器重复判定一次
            System.out.println("当前位置："+ row +","+ col + "已经有子了");
            return;
        }


        board[row][col] = chess;

        //+++ 打印棋盘信息
        printBoard();

        //2、进行胜负判定
        int winner = checkWinner(row,col,chess);

        //3.给房间中的所有客户端都返回响应数据
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);

        WebSocketSession session1 = onlineUserManager.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManager.getFromGameRoom(user2.getUserId());

        //判定当前会话是否为空 玩家下线

        if(session1 == null){
            //玩家 1 下线 直接玩家 2 获胜
            response.setWinner(user2.getUserId());
            System.out.println("玩家2获胜");
        }

        if(session2 == null){
            response.setWinner(user1.getUserId());
            System.out.println("玩家1获胜");
        }
        String respJson = objectMapper.writeValueAsString(response);
        if(session1 != null){
            session1.sendMessage(new TextMessage(respJson));
        }

        if(session2 != null){
            session2.sendMessage(new TextMessage(respJson));
        }

        //胜负已分
        if(response.getWinner() != 0){
            System.out.println("游戏即将结束！房间即将销毁！roomId" + roomId + "获胜方：" + response.getWinner());
            //更新获胜方和失败方的信息

            int winUserId = response.getWinner();
            int loseUserId = response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId();

            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);

            //销毁房间
            roomService.remove(roomId,user1.getUserId(),user2.getUserId());
        }
    }

    //打印出棋盘
    private void printBoard() {
        System.out.println("打印棋盘信息");
        System.out.println("=========================================");
        for (int r = 0; r < maxRow; r++) {
            for (int c = 0; c < maxCol; c++) {
                System.out.print(board[r][c] + " ");
            }

            System.out.println();
        }
        System.out.println("=========================================");
    }

    //TODO:
    //使用这个方法判断是否分出胜负 玩家1胜返回玩家1 id 反之返回 玩家2 的id 胜负未分：返回 0
    private int checkWinner(int row, int col, int chess) {
        //检查所有的行

        //先遍历这五种情况 判断这个五个子是不是连在一起 不光是五个子是连着的 而且是当前玩家下的
        for (int c = col - 4; c <= col ; c++) {
            try {
                if(board[row][c] == chess
                  && board[row][c+1] == chess
                  && board[row][c+2] == chess
                  && board[row][c+3] == chess
                  && board[row][c+4] == chess){
                    //胜负已经分出来了
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                //出现越界直接忽略
                continue;
            }
        }

        //检查所有列
        for (int r = row - 4; r <= row ; r++) {
            try{
                if(board[r][col] == chess
                && board[r+1][col] == chess
                && board[r+2][col] == chess
                && board[r+3][col] == chess
                && board[r+4][col] == chess){
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        
        //检查左对角线
        for (int c = col - 4, r = row - 4; c <= col && r <= row ;r++, c++) {
            try{
                if(board[r][c] == chess
                && board[r+1][c+1] == chess
                && board[r+2][c+2] == chess
                && board[r+3][c+3] == chess
                && board[r+4][c+4] == chess){
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        
        //检查右对角线
        for (int c = col + 4, r = row - 4; c >= col && r <= row ;r++, c--) {
            try{
                if(board[r][c] == chess
                  && board[r+1][c-1] == chess
                  && board[r+2][c-2] == chess
                  && board[r+3][c-3] == chess
                  && board[r+4][c-4] == chess){
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        //胜负未分 返回 0
        return 0;
    }
}



